#include <stdio.h>
#include <getopt.h>

/*
 * binary_edit.c
 *
 * this program modifies input binary file with csv file.
 *
 * required csv file format
 *   from,to,val
 *   from,to,val
 *   from,to,val
 *   .
 *   .
 *
 *   ex1) 1,1,3  # write 3 at address 1
 *   ex2) 4,6,-1 # delete from address 4 to address 6
 *   ex3) 9,0,0  # write 0 from address 9 to the end of file
 */

#define PARAM_IS_HEX   4

void usage( char **argv ) {

  printf( "usage : %s [options] <csv file> <input binary file> <output binary file>\n", argv[ 0 ] ) ;
  printf( "\n" ) ;
  printf( "[options]\n" ) ;
  printf( "  -h : show this message and exit.\n" ) ;
  printf( "  -x : the parameters in csv are hex.\n" ) ;
  return ;

}

unsigned int next_param( unsigned int flag, FILE *fp, int *from, int *to, int *val ) {

  if( flag & PARAM_IS_HEX )
    return fscanf( fp, "%x,%x,%x\n", from, to, val ) == EOF ? 0 : 1 ;

  return fscanf( fp, "%d,%d,%d\n", from, to, val ) == EOF ? 0 : 1 ;

}

void put_val( int val, FILE *fp ) {
  if( val >= 0 )
    putc( val, fp ) ;
}

int main( int argc, char **argv ) {

  FILE *fcsv, *fin, *fout ;
  int c, opt, from, to, val ;
  unsigned int i = 0, flag = 0, opt_count = 0, has_next = 0 ;

  while( ( opt = getopt( argc, argv, "hx" ) ) != -1 ) {
    switch( opt ) {
      case 'h' :
        usage( argv ) ;
        return 0 ;
      case 'x' :
        flag |= PARAM_IS_HEX ;
        opt_count++ ;
        break ;
      default :
        usage( argv ) ;
        return -1 ;
    }
  }

  if( argc - opt_count != 4 ) {
    usage( argv ) ;
    return -1 ;
  }

  if( ! ( fcsv = fopen( argv[ optind + 0 ], "r" ) ) ) {
    printf( "failed to open csv file.\n" ) ;
    return -1 ;
  }

  if( ! ( fin = fopen( argv[ optind + 1 ], "rb" ) ) ) {
    printf( "failed to open input file.\n" ) ;
    fclose( fcsv ) ;
    return -1 ;
  }

  if( ! ( fout = fopen( argv[ optind + 2 ], "wb" ) ) ) {
    printf( "failed to open open file.\n" ) ;
    fclose( fcsv ) ;
    fclose( fin ) ;
    return -1 ;
  }

  has_next = next_param( flag, fcsv, &from, &to, &val ) ;
  while( ( c = getc( fin ) ) != EOF ) {
    if( ! has_next ) {
      putc( c, fout ) ;
    } else if( from == to && i == from ) {
      put_val( val, fout ) ;
      has_next = next_param( flag, fcsv, &from, &to, &val ) ;
    } else if( from < to && i >= from && i <= to ) {
      put_val( val, fout ) ;
      if( i == to ) {
        has_next = next_param( flag, fcsv, &from, &to, &val ) ;
      }
    } else if( from > to && i >= to ) {
      put_val( val, fout ) ;
    } else {
      putc( c, fout ) ;
    }
    i++ ;
  }

  fclose( fout ) ;
  fclose( fin ) ;
  fclose( fcsv ) ;

  return 0 ;

}

